using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Senparc.Weixin.Work.AdvancedAPIs;
using Senparc.Weixin.Work.AdvancedAPIs.OAuth2;
using Senparc.Weixin.Work.AdvancedAPIs.MailList;
using Senparc.Weixin.Work.CommonAPIs;
using Senparc.Weixin.Work.Containers;
using Senparc.Weixin.Work.Entities;
using Senparc.CO2NET.Cache;
using System.Text.Json;
using Lzfy_His_Service.Models.Configuration;
using Lzfy_His_Service.Models;
using Lzfy_His_Service.Exceptions;
using Lzfy_His_Service.Logging;

namespace Lzfy_His_Service.Services
{
    /// <summary>
    /// Senparc企业微信服务实现
    /// </summary>
    public class SenparcWeChatService : ISenparcWeChatService
    {
        private readonly SenparcWeChatConfiguration _config;
        private readonly ILogger<SenparcWeChatService> _logger;
        private readonly ISenparcCacheService _cacheService;
        private readonly IHttpClientFactory _httpClientFactory;

        public SenparcWeChatService(
            IOptions<SenparcWeChatConfiguration> config,
            ILogger<SenparcWeChatService> logger,
            ISenparcCacheService cacheService,
            IHttpClientFactory httpClientFactory)
        {
            _config = config.Value ?? throw new ArgumentNullException(nameof(config));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _cacheService = cacheService ?? throw new ArgumentNullException(nameof(cacheService));
            _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));

            ValidateConfiguration();
        }

        /// <summary>
        /// 获取企业微信授权URL
        /// </summary>
        /// <param name="redirectUri">回调地址</param>
        /// <param name="state">状态参数</param>
        /// <returns>授权URL</returns>
        public async Task<string> GetAuthUrlAsync(string redirectUri, string state = null)
        {
            try
            {
                if (!_config.Enabled)
                {
                    throw new WeChatConfigException("WECHAT_DISABLED", "企业微信登录功能已禁用");
                }

                // 使用配置的回调地址或传入的回调地址
                var finalRedirectUri = !string.IsNullOrEmpty(redirectUri) ? redirectUri : _config.RedirectUri;
                
                if (string.IsNullOrEmpty(finalRedirectUri))
                {
                    throw new WeChatConfigException("REDIRECT_URI_MISSING", "回调地址未配置");
                }

                // 生成状态参数
                var finalState = !string.IsNullOrEmpty(state) ? state : Guid.NewGuid().ToString("N")[..16];

                // 构建授权URL
                var authUrl = OAuth2Api.GetCode(
                    _config.CorpId,
                    finalRedirectUri,
                    finalState,
                    _config.AgentId);

                _logger.LogAuthUrlGenerated(authUrl, finalState);

                return authUrl;
            }
            catch (Exception ex) when (!(ex is WeChatConfigException))
            {
                _logger.LogError(ex, "获取企业微信授权URL失败");
                throw new WeChatApiException("GET_AUTH_URL_FAILED", "获取授权URL失败");
            }
        }

        /// <summary>
        /// 通过授权码获取用户信息
        /// </summary>
        /// <param name="code">授权码</param>
        /// <returns>用户信息</returns>
        public async Task<OAuth2_GetUserInfoResult> GetUserInfoAsync(string code)
        {
            if (string.IsNullOrEmpty(code))
            {
                throw new ArgumentException("授权码不能为空", nameof(code));
            }

            try
            {
                // 获取AccessToken
                var accessToken = await GetAccessTokenAsync();

                // 通过授权码获取用户信息
                var userInfoResult = await OAuth2Api.GetUserInfoAsync(accessToken, code);

                if (userInfoResult.errcode != Senparc.Weixin.ReturnCode_Work.请求成功)
                {
                    _logger.LogApiCallFailed("GetUserInfo", userInfoResult.errcode.ToString(), userInfoResult.errmsg);
                    throw new WeChatApiException(userInfoResult.errcode.ToString(), userInfoResult.errmsg);
                }

                _logger.LogUserInfoRetrieved(userInfoResult.UserId, userInfoResult.name ?? "未知");

                return userInfoResult;
            }
            catch (Exception ex) when (!(ex is WeChatApiException))
            {
                _logger.LogError(ex, "获取用户信息失败，授权码：{Code}", code);
                throw new WeChatApiException("GET_USER_INFO_FAILED", "获取用户信息失败");
            }
        }

        /// <summary>
        /// 获取成员详细信息
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns>成员信息</returns>
        public async Task<GetMemberResult> GetMemberInfoAsync(string userId)
        {
            if (string.IsNullOrEmpty(userId))
            {
                throw new ArgumentException("用户ID不能为空", nameof(userId));
            }

            try
            {
                // 先尝试从缓存获取
                var cachedUserInfo = await _cacheService.GetUserInfoAsync(userId);
                if (cachedUserInfo != null)
                {
                    // 将缓存的用户信息转换为GetMemberResult
                    return ConvertToGetMemberResult(cachedUserInfo);
                }

                // 获取AccessToken
                var accessToken = await GetAccessTokenAsync();

                // 获取成员详细信息
                var memberResult = await MailListApi.GetMemberAsync(accessToken, userId);

                if (memberResult.errcode != Senparc.Weixin.ReturnCode_Work.请求成功)
                {
                    _logger.LogApiCallFailed("GetMember", memberResult.errcode.ToString(), memberResult.errmsg);
                    throw new WeChatApiException(memberResult.errcode.ToString(), memberResult.errmsg);
                }

                // 缓存用户信息
                var userInfo = ConvertToWeChatUserInfo(memberResult);
                await _cacheService.SetUserInfoAsync(userId, userInfo, TimeSpan.FromSeconds(_config.Cache.UserInfoCacheSeconds));

                _logger.LogInformation("获取成员详细信息成功：{UserId} - {Name}", userId, memberResult.name);

                return memberResult;
            }
            catch (Exception ex) when (!(ex is WeChatApiException))
            {
                _logger.LogError(ex, "获取成员详细信息失败，用户ID：{UserId}", userId);
                throw new WeChatApiException("GET_MEMBER_INFO_FAILED", "获取成员详细信息失败");
            }
        }

        /// <summary>
        /// 验证企业微信签名
        /// </summary>
        /// <param name="signature">签名</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">随机数</param>
        /// <param name="echostr">验证字符串</param>
        /// <returns>验证结果</returns>
        public async Task<bool> ValidateSignatureAsync(string signature, string timestamp, string nonce, string echostr)
        {
            try
            {
                if (string.IsNullOrEmpty(_config.Token))
                {
                    throw new WeChatConfigException("TOKEN_MISSING", "企业微信Token未配置");
                }

                // 使用Senparc.Weixin的签名验证方法
                var isValid = Senparc.Weixin.Work.Signature.Check(signature, timestamp, nonce, _config.Token);

                _logger.LogInformation("企业微信签名验证结果：{IsValid}，签名：{Signature}", isValid, signature);

                return await Task.FromResult(isValid);
            }
            catch (Exception ex) when (!(ex is WeChatConfigException))
            {
                _logger.LogError(ex, "验证企业微信签名失败");
                return false;
            }
        }

        /// <summary>
        /// 获取JS-SDK配置
        /// </summary>
        /// <param name="url">当前页面URL</param>
        /// <returns>JS-SDK配置</returns>
        public async Task<JsApiTicketResult> GetJsApiConfigAsync(string url)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentException("页面URL不能为空", nameof(url));
            }

            try
            {
                // 获取JsApiTicket
                var jsApiTicket = await GetJsApiTicketAsync();

                // 生成签名所需的参数
                var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                var nonceStr = Guid.NewGuid().ToString("N")[..16];

                // 生成签名
                var signature = Senparc.Weixin.Work.CommonAPIs.JsApiTicketContainer.GenerateSignature(
                    jsApiTicket, nonceStr, timestamp.ToString(), url);

                var result = new JsApiTicketResult
                {
                    CorpId = _config.CorpId,
                    AgentId = _config.AgentId,
                    Timestamp = timestamp,
                    NonceStr = nonceStr,
                    Signature = signature,
                    JsApiTicket = jsApiTicket
                };

                _logger.LogInformation("生成JS-SDK配置成功，URL：{Url}", url);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取JS-SDK配置失败，URL：{Url}", url);
                throw new WeChatApiException("GET_JSAPI_CONFIG_FAILED", "获取JS-SDK配置失败");
            }
        }

        /// <summary>
        /// 发送企业微信消息
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <param name="message">消息内容</param>
        /// <returns>发送结果</returns>
        public async Task<SendMessageResult> SendMessageAsync(string userId, string message)
        {
            if (string.IsNullOrEmpty(userId))
            {
                throw new ArgumentException("用户ID不能为空", nameof(userId));
            }

            if (string.IsNullOrEmpty(message))
            {
                throw new ArgumentException("消息内容不能为空", nameof(message));
            }

            try
            {
                // 获取AccessToken
                var accessToken = await GetAccessTokenAsync();

                // 构建消息数据
                var messageData = new
                {
                    touser = userId,
                    msgtype = "text",
                    agentid = _config.AgentId,
                    text = new { content = message },
                    safe = 0
                };

                // 发送消息
                var result = await Senparc.Weixin.Work.AdvancedAPIs.MassApi.SendTextAsync(
                    accessToken, _config.AgentId, message, userId);

                if (result.errcode != Senparc.Weixin.ReturnCode_Work.请求成功)
                {
                    _logger.LogApiCallFailed("SendMessage", result.errcode.ToString(), result.errmsg);
                    throw new WeChatApiException(result.errcode.ToString(), result.errmsg);
                }

                var sendResult = new SendMessageResult
                {
                    Success = true,
                    MessageId = result.msgid,
                    ErrorCode = result.errcode.ToString(),
                    ErrorMessage = result.errmsg
                };

                _logger.LogInformation("发送企业微信消息成功，用户：{UserId}，消息ID：{MessageId}", userId, result.msgid);

                return sendResult;
            }
            catch (Exception ex) when (!(ex is WeChatApiException))
            {
                _logger.LogError(ex, "发送企业微信消息失败，用户：{UserId}", userId);
                throw new WeChatApiException("SEND_MESSAGE_FAILED", "发送消息失败");
            }
        }

        #region 私有方法

        /// <summary>
        /// 获取AccessToken
        /// </summary>
        /// <returns>AccessToken</returns>
        private async Task<string> GetAccessTokenAsync()
        {
            try
            {
                // 先尝试从缓存获取
                var cachedToken = await _cacheService.GetAccessTokenAsync();
                if (!string.IsNullOrEmpty(cachedToken))
                {
                    return cachedToken;
                }

                // 从企业微信API获取新的AccessToken
                var tokenResult = await CommonApi.GetTokenAsync(_config.CorpId, _config.CorpSecret);

                if (tokenResult.errcode != Senparc.Weixin.ReturnCode_Work.请求成功)
                {
                    _logger.LogApiCallFailed("GetAccessToken", tokenResult.errcode.ToString(), tokenResult.errmsg);
                    throw new WeChatApiException(tokenResult.errcode.ToString(), tokenResult.errmsg);
                }

                // 缓存AccessToken
                var expiry = TimeSpan.FromSeconds(_config.Cache.AccessTokenCacheSeconds);
                await _cacheService.SetAccessTokenAsync(tokenResult.access_token, expiry);

                _logger.LogInformation("获取AccessToken成功，过期时间：{ExpiresIn}秒", tokenResult.expires_in);

                return tokenResult.access_token;
            }
            catch (Exception ex) when (!(ex is WeChatApiException))
            {
                _logger.LogError(ex, "获取AccessToken失败");
                throw new WeChatApiException("GET_ACCESS_TOKEN_FAILED", "获取访问令牌失败");
            }
        }

        /// <summary>
        /// 获取JsApiTicket
        /// </summary>
        /// <returns>JsApiTicket</returns>
        private async Task<string> GetJsApiTicketAsync()
        {
            try
            {
                // 先尝试从缓存获取
                var cachedTicket = await _cacheService.GetJsApiTicketAsync();
                if (!string.IsNullOrEmpty(cachedTicket))
                {
                    return cachedTicket;
                }

                // 获取AccessToken
                var accessToken = await GetAccessTokenAsync();

                // 从企业微信API获取新的JsApiTicket
                var ticketResult = await CommonApi.GetTicketAsync(accessToken, "jsapi");

                if (ticketResult.errcode != Senparc.Weixin.ReturnCode_Work.请求成功)
                {
                    _logger.LogApiCallFailed("GetJsApiTicket", ticketResult.errcode.ToString(), ticketResult.errmsg);
                    throw new WeChatApiException(ticketResult.errcode.ToString(), ticketResult.errmsg);
                }

                // 缓存JsApiTicket
                var expiry = TimeSpan.FromSeconds(_config.Cache.JsApiTicketCacheSeconds);
                await _cacheService.SetJsApiTicketAsync(ticketResult.ticket, expiry);

                _logger.LogInformation("获取JsApiTicket成功，过期时间：{ExpiresIn}秒", ticketResult.expires_in);

                return ticketResult.ticket;
            }
            catch (Exception ex) when (!(ex is WeChatApiException))
            {
                _logger.LogError(ex, "获取JsApiTicket失败");
                throw new WeChatApiException("GET_JSAPI_TICKET_FAILED", "获取JS接口票据失败");
            }
        }

        /// <summary>
        /// 验证配置
        /// </summary>
        private void ValidateConfiguration()
        {
            if (string.IsNullOrEmpty(_config.CorpId))
            {
                throw new WeChatConfigException("CORP_ID_MISSING", "企业ID未配置");
            }

            if (string.IsNullOrEmpty(_config.CorpSecret))
            {
                throw new WeChatConfigException("CORP_SECRET_MISSING", "企业密钥未配置");
            }

            if (string.IsNullOrEmpty(_config.AgentId))
            {
                throw new WeChatConfigException("AGENT_ID_MISSING", "应用ID未配置");
            }
        }

        /// <summary>
        /// 转换为WeChatUserInfoResponse
        /// </summary>
        /// <param name="memberResult">成员信息</param>
        /// <returns>用户信息响应</returns>
        private static WeChatUserInfoResponse ConvertToWeChatUserInfo(GetMemberResult memberResult)
        {
            return new WeChatUserInfoResponse
            {
                UserId = memberResult.userid,
                Name = memberResult.name,
                Mobile = memberResult.mobile,
                Department = memberResult.department,
                Position = memberResult.position,
                Avatar = memberResult.avatar,
                Email = memberResult.email
            };
        }

        /// <summary>
        /// 转换为GetMemberResult
        /// </summary>
        /// <param name="userInfo">用户信息</param>
        /// <returns>成员信息结果</returns>
        private static GetMemberResult ConvertToGetMemberResult(WeChatUserInfoResponse userInfo)
        {
            return new GetMemberResult
            {
                userid = userInfo.UserId,
                name = userInfo.Name,
                mobile = userInfo.Mobile,
                department = userInfo.Department,
                position = userInfo.Position,
                avatar = userInfo.Avatar,
                email = userInfo.Email,
                errcode = Senparc.Weixin.ReturnCode_Work.请求成功,
                errmsg = "ok"
            };
        }

        #endregion
    }

    /// <summary>
    /// 发送消息结果
    /// </summary>
    public class SendMessageResult
    {
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool Success { get; set; }
        
        /// <summary>
        /// 消息ID
        /// </summary>
        public string MessageId { get; set; } = string.Empty;
        
        /// <summary>
        /// 错误代码
        /// </summary>
        public string ErrorCode { get; set; } = string.Empty;
        
        /// <summary>
        /// 错误消息
        /// </summary>
        public string ErrorMessage { get; set; } = string.Empty;
    }

    /// <summary>
    /// JS-SDK票据结果
    /// </summary>
    public class JsApiTicketResult
    {
        /// <summary>
        /// 企业ID
        /// </summary>
        public string CorpId { get; set; } = string.Empty;
        
        /// <summary>
        /// 应用ID
        /// </summary>
        public string AgentId { get; set; } = string.Empty;
        
        /// <summary>
        /// 时间戳
        /// </summary>
        public long Timestamp { get; set; }
        
        /// <summary>
        /// 随机字符串
        /// </summary>
        public string NonceStr { get; set; } = string.Empty;
        
        /// <summary>
        /// 签名
        /// </summary>
        public string Signature { get; set; } = string.Empty;
        
        /// <summary>
        /// JS接口票据
        /// </summary>
        public string JsApiTicket { get; set; } = string.Empty;
    }
}